home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / coledit.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  64KB  |  2,525 lines

  1. /*
  2.  * $Id: coledit.c,v 0.91 1994/02/20 00:53:21 zhao Pre-Release $
  3.  *
  4.  *. This file is part of BIT shareware package. After the two weeks of
  5.  *  free evaluation period, you are encouraged (required) to register
  6.  *  your copy for a small registration fee, which is $35 for personal use
  7.  *  and $50 for commercial, government and institutional use.
  8.  *
  9.  *  Copyright(c) 1993, 1994 by T.C. Zhao.
  10.  *  All rights reserved.
  11.  *
  12.  *  Permission to use, copy, and distribute this software in its entirety
  13.  *  for non-commercial purposes is hereby granted, provided that the
  14.  *  above shareware and copyright notices and this permission notice
  15.  *  appear in all copies and their documentation.
  16.  *
  17.  *  This software may be modified for your own use, but modified versions
  18.  *  may not be distributed without prior consent of the author.
  19.  *
  20.  *  This software is provided "as is" without expressed or implied
  21.  *  warranty of any kind.
  22.  *
  23.  *.
  24.  *
  25.  * This file contains
  26.  *  A. Get the color transformation functions.
  27.  *  B. Color selection routines.
  28.  *  C. Color Map editing
  29.  */
  30. #if !defined(lint) && defined(F_ID)
  31. char *id_ced = "$Id: coledit.c,v 0.91 1994/02/20 00:53:21 zhao Pre-Release $";
  32. #endif
  33.  
  34. #include "bit.h"
  35. #include "extern.h"
  36.  
  37. /*********************************************************************
  38.  * Arbitary one to one transformations
  39.  *
  40.  *******************************************************************{*/
  41.  
  42. /******************* Limits and defines *************************/
  43.  
  44. #define MINPNTS   3        /* min. no. of cntrl pnts             */
  45. #define MAXPNTS   34        /* max. no. of cntrl pnts must be even */
  46.  
  47. /******************* Local variables ****************************/
  48.  
  49. static float fx[3][MAXPNTS], fy[3][MAXPNTS];    /* the func */
  50.  
  51. static IPTR saved;        /* local image                          */
  52. static int c0, c1;        /* currently active color               */
  53. static int changed;        /* true if image is modified            */
  54. static int reg;            /* if apply to a piece of the image     */
  55. static int rx, ry, rw, rh;    /* region size                          */
  56. static int lastswap = -1;    /* -1 indicate indentity transformation */
  57. static int pswtbl[2][4];    /* pixel swap table                     */
  58.  
  59. /* default no. of control points */
  60. static int lastn[3] =
  61. {
  62.     9, 9, 9
  63. };
  64.  
  65.  
  66. static FL_FORM *coledit;    /* main form               */
  67.  
  68. /****************** Local functions *************************/
  69.  
  70. static void create_form_coledit(void);
  71. static int init_pixtran(IPTR, int);
  72. static void pix2_done(FL_OBJECT *, long);
  73. static void init_func(void);
  74. static void invert_it(void);
  75. static void quant_it(void);
  76. static void band_it(void);
  77. static void detail_it(void);
  78. static void threshold(void);
  79. static void dd_bb(void);
  80. static void pix_replace(void);
  81. static void pix_swap(void);
  82. static void dn_shift(void);
  83. static void up_shift(void);
  84. static void math_exp(void);
  85.  
  86. /******************************************************************
  87.  * Predefined shortcuts
  88.  *****************************************************************/
  89.  
  90. typedef struct
  91.   {
  92.       const char *l;        /* name of the function */
  93.       int col;            /* color when pressed   */
  94.       VVfptr f;            /* the function itself  */
  95.   }
  96. shortcut_t;
  97.  
  98.  
  99. static shortcut_t sc[] =
  100. {
  101.     {"Reset", FL_GREEN, init_func},    /* initialize to identity */
  102.     {"Invert", FL_YELLOW, invert_it},    /* photo inversion        */
  103.     {"Steps", FL_YELLOW, quant_it},    /* step quantization      */
  104.     {"Band", FL_YELLOW, band_it},    /* band clustering        */
  105.     {"Threshold", FL_YELLOW, threshold},    /* thresholding           */
  106.     {"Log(1+ax)", FL_YELLOW, detail_it},    /* intensify weak pixels  */
  107.     {"Dnshift", FL_YELLOW, dn_shift},    /* shift down 1 bit       */
  108.     {"Upshift", FL_YELLOW, up_shift},    /* shift up 1 bit         */
  109.     {"Contrast", FL_YELLOW, dd_bb},    /* dark darker, bright brighter */
  110.     {"SwapPix", FL_YELLOW, pix_swap},    /* pixel swap             */
  111.     {"ChangePix", FL_YELLOW, pix_replace},
  112.     {"MathExp", FL_YELLOW, math_exp}    /* math expressions      */
  113. };
  114.  
  115.  
  116. /****************************************************************
  117.  *   Global entry point
  118.  ****************************************************************/
  119. int
  120. do_coledit(IPTR im)
  121. {
  122.     long dev;
  123.     short val;
  124.  
  125.     create_form_coledit();
  126.  
  127.     /* initialize and install window managers resize and reposition events */
  128.     init_pixtran(im, 0);
  129.     install_wm_handler(init_pixtran);
  130.  
  131.     /* force rectangular region */
  132.     set_rubber_obj(RB_RECT);
  133.  
  134.     /* save current image */
  135.     free_image(saved);
  136.     saved = img_dup(im);
  137.  
  138.     bit_show_form(coledit, FL_PLACE_MOUSE, 0, "ColorEdit");
  139.  
  140.     /* looping until ESC or Done button clicking */
  141.     do
  142.       {
  143.       dev = rubber_info(win_id, &val, &rx, &ry, &rw, &rh, 3, 15);
  144.       dev = bit_handle_event(dev, val);
  145.       }
  146.     while (dev != KEYBD || val != 27);
  147.  
  148.     set_current_window(win_id);
  149.     rubber_finish();
  150.     bit_hide_form(coledit);
  151.     pix2_done(0, 0);
  152.     free_image(saved);
  153.     getstring_finish();
  154.     saved = 0;
  155.     return 0;
  156. }
  157.  
  158. /******* More GUI variavles **********/
  159.  
  160. static FL_OBJECT *ncounter;
  161. static FL_OBJECT *fcol[3], *tranfg;
  162. static FL_OBJECT *gm, *app[4];
  163. static const char *xl = "Input", *yl = "Output";
  164.  
  165. /***************************************************************
  166.  * Evaluate a math expression given by str.
  167.  * The parser uses the fx as variable values and generates the
  168.  * corresponding fy.
  169.  ***************************************************************/
  170.  
  171. static void
  172. parse_it(const char *str)
  173. {
  174.     int j, err;
  175.  
  176.     if (!str || !*str)
  177.     return;
  178.  
  179.     fl_freeze_form(coledit);
  180.  
  181.     for (err = 0, j = c0; !err && j < c1; j++)
  182.       {
  183.       if (!(err = rd_evaluate(str, fx[j], fy[j], lastn[j])))
  184.         {
  185.         fl_add_xyplot_text(fcol[j], 0.40, 0.92, 0, str, 0,
  186.                    FL_BLACK, FL_SMALL_FONT, FL_NORMAL_STYLE);
  187.         fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
  188.         }
  189.       }
  190.     fl_unfreeze_form(coledit);
  191.  
  192.     /* an error has occured. Don't bark */
  193.     if (err)
  194.     M_err("MathExp", "Error parsing %s", str);
  195. }
  196.  
  197. /***************************************************************
  198.  * Get the math expression and call the parser evaluate it.
  199.  ***************************************************************/
  200. static void
  201. math_exp(void)
  202. {
  203.     set_getstring_cb(parse_it);
  204.     getstring("Math Expression", "", 0);
  205. }
  206.  
  207.  
  208. /***************************************************************
  209.  * do the shortcuts. pix_swap and pix_replace is speical
  210.  * in that they are NOT 1-to-1 transformations of color channels,
  211.  * but rather PIXEL 1-to-1.
  212.  **************************************************************/
  213. /* ARGSUSED */
  214. static void
  215. do_short_cuts(FL_OBJECT * q, long p)
  216. {
  217.     VVfptr func = (sc + p)->f;
  218.  
  219.     if (func != pix_swap && func != pix_replace)
  220.     lastswap = 0;
  221.  
  222.     /* execute the shortcut function */
  223.     func();
  224. }
  225.  
  226.  
  227. /*********************************************************
  228.  * reset current transformation to null, i.e., y(x) = x
  229.  **********************************************************/
  230.  
  231. static void
  232. init_func(void)
  233. {
  234.     int i, j, n;
  235.     float *x, *y;
  236.  
  237.     fl_freeze_form(coledit);
  238.  
  239.     for (j = 3; --j >= 0;)
  240.       {
  241.       n = lastn[j];
  242.       for (x = fx[j], y = fy[j], i = 0; i < n; i++)
  243.           x[i] = y[i] = (float) i / (n - 1);
  244.       fl_clear_xyplot_text(fcol[j]);
  245.       fl_set_xyplot(fcol[j], x, y, n, "", xl, yl);
  246.       }
  247.  
  248.     /* reset misc. info as well */
  249.     fl_set_counter_value(gm, 1.0);
  250.     fl_unfreeze_form(coledit);
  251.  
  252.     /* signify identity transformation */
  253.     lastswap = -1;
  254. }
  255.  
  256. /***************************************************************
  257.  * if individual control point changes, show the new value and
  258.  * also set other channel's value
  259.  *****************************************************************/
  260. /* ARGSUSED */
  261. static void
  262. show_it(FL_OBJECT * p, long q)
  263. {
  264.     float x, y;
  265.     int ix, iy, i, j, n;
  266.     char ss[100];
  267.  
  268.     fl_get_active_xyplot(p, &x, &y, &i);
  269.     ix = (x * PCMAXV + 0.5);
  270.     iy = (y * PCMAXV + 0.5);
  271.  
  272.     sprintf(ss, "(%3d %3d)", ix, iy);
  273.     n = lastn[q];
  274.  
  275.     fl_freeze_form(coledit);
  276.     fl_add_xyplot_text(p, 0.40, 0.92, 0, ss, 0, FL_BLACK,
  277.                FL_SMALL_FONT, FL_NORMAL_STYLE);
  278.     for (j = c0; j < c1; j++)
  279.       {
  280.       if (n != lastn[j])
  281.           continue;
  282.  
  283.       if (p != fcol[j])
  284.         {
  285.         /* clear old text */
  286.         fl_clear_xyplot_text(fcol[j]);
  287.         fl_set_xyplot_point(fcol[j], x, y, i);
  288.         fx[j][i] = x;
  289.         fy[j][i] = y;
  290.         }
  291.       }
  292.     lastswap = 0;
  293.     fl_unfreeze_form(coledit);
  294. }
  295.  
  296. /* Color to which transformation applies changes */
  297. /* ARGSUSED */
  298. static void
  299. cind_cb(FL_OBJECT * p, long q)
  300. {
  301.     if (q == 3)
  302.       {
  303.       c0 = 0;
  304.       c1 = 3;
  305.       }
  306.     else
  307.       {
  308.       c0 = q;
  309.       c1 = q + 1;
  310.       }
  311. }
  312.  
  313. /****** insert one point ********/
  314. static void
  315. finer(void)
  316. {
  317.     int i, j, ij;
  318.     float dx, ddx, *x, *y;
  319.  
  320.     for (j = c0; j < c1; j++)
  321.       {
  322.       x = fx[j];
  323.       y = fy[j];
  324.       /* get the max dx and insert a point there */
  325.       for (ij = 1, dx = 0.0, i = 1; i < lastn[j]; i++)
  326.         {
  327.         ddx = x[i] - x[i - 1];
  328.         if (dx < ddx)
  329.           {
  330.               ij = i;
  331.               dx = ddx;
  332.           }
  333.         }
  334.       /* do the insertion */
  335.       for (i = lastn[j]; i > ij; i--)
  336.         {
  337.         x[i] = x[i - 1];
  338.         y[i] = y[i - 1];
  339.         }
  340.  
  341.       x[ij] = (x[ij - 1] + x[ij + 1]) * 0.5;
  342.       y[ij] = (y[ij - 1] + y[ij + 1]) * 0.5;
  343.  
  344.       lastn[j] += 1;
  345.       }
  346. }
  347.  
  348. /********* remove one point ************/
  349. static void
  350. coarse(void)
  351. {
  352.     int i, j, ij;
  353.     float dx, ddx, *x, *y;
  354.  
  355.     for (j = c0; j < c1; j++)
  356.       {
  357.       x = fx[j];
  358.       y = fy[j];
  359.       /* get the min dx and delete a point on the right there */
  360.       for (ij = 1, dx = 1.0, i = 1; i < lastn[j]; i++)
  361.         {
  362.         ddx = x[i] - x[i - 1];
  363.         if (dx > ddx)
  364.           {
  365.               ij = i;
  366.               dx = ddx;
  367.           }
  368.         }
  369.       /* do the deletion. take care not to delete last point */
  370.       if (ij == lastn[j] - 1)
  371.         {
  372.         x[ij - 1] = x[ij];
  373.         y[ij - 1] = y[ij];
  374.         }
  375.       lastn[j] -= 1;
  376.       for (i = ij; i < lastn[j]; i++)
  377.         {
  378.         x[i] = x[i + 1];
  379.         y[i] = y[i + 1];
  380.         }
  381.       }
  382. }
  383.  
  384. /************* add points ****************/
  385. /* ARGSUSED */
  386. static void
  387. pnts_cb(FL_OBJECT * p, long q)
  388. {
  389.     int i, j, cn;
  390.     int n = (fl_get_counter_value(p) + 0.5);
  391.  
  392.     for (j = c0; j < c1; j++)
  393.       {
  394.       cn = lastn[j];    /* must save no. of points. */
  395.       if (n > lastn[j])
  396.         {            /* add */
  397.         for (i = 0; i < n - cn; i++)
  398.             finer();
  399.         }
  400.       else
  401.         {
  402.         for (i = 0; i < cn - n; i++)
  403.             coarse();
  404.         }
  405.       fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
  406.       }
  407. }
  408.  
  409. /****************************************************************
  410.  * Check if the transformation is be applied to a (rectabgular)
  411.  * region of the image and if so, return the subimage
  412.  ****************************************************************/
  413.  
  414. static void *
  415. check_if_region(void)
  416. {
  417.     void *pp = 0;
  418.  
  419.     /* check if the transformation is to be applied to a region */
  420.     reg = (rx - imgptr->xi) || (ry - imgptr->yi) ||
  421.     (rw - imgptr->w) || (rh - imgptr->h);
  422.  
  423.     /*
  424.      * if transformation is requested for a region, need to get the image for
  425.      * the requested region and convert image to RGB
  426.      */
  427.  
  428.     if (reg)
  429.       {
  430.       if (IS_CI(imgptr))
  431.         {
  432.         show_busy("Converting to RGB ...");
  433.         (void) img_convert_type(imgptr, T_RGBA);
  434.         imgptr->io->display(imgptr, 0, 0);
  435.         }
  436.  
  437.       if (!(pp = get_subimage(imgptr, rx, ry, rw, rh)))
  438.         {
  439.         Bark("ColEdit_Region", "Unable to get submatrix");
  440.         }
  441.       }
  442.     return pp;
  443. }
  444.  
  445. /****************************************************************
  446.  * Do the pixel swapping (latswap == 2)  and replace (lastswap==1)
  447.  * In case the transformation is to be applied to a region,
  448.  * pp would contain the subimage
  449.  *****************************************************************/
  450. static void
  451. swap_pixels(void **pp)
  452. {
  453.     long total = rw * rh;
  454.  
  455.     if (reg && pp)
  456.       {
  457.       modify_cpack_pixel(pp[0], total,
  458.                  Pack(pswtbl[0][0], pswtbl[0][1], pswtbl[0][2]),
  459.                  Pack(pswtbl[1][0], pswtbl[1][1], pswtbl[1][2]),
  460.                  lastswap == 2);
  461.       put_subimage(imgptr, pp, make_rect(rx, ry, rw, rh), 1);
  462.       set_current_window(win_id);
  463.       Rectwrite(rx, ry, rx + rw - 1, ry + rh - 1, pp[0]);
  464.       free_mat(pp);
  465.       }
  466.     else
  467.       {
  468.       img_modify_pixel(imgptr, pswtbl[0], pswtbl[1], lastswap == 2);
  469.       imgptr->io->display(imgptr, 2, 0);
  470.       }
  471. }
  472.  
  473. /*******************************************************************
  474.  * Do the general transformations: rgb contains the normalized
  475.  * tranformation functions
  476.  *******************************************************************/
  477.  
  478. static void
  479. do_gen_tran(void **pp, pc_t rgb[][PCMAX])
  480. {
  481.  
  482.     if (!reg)
  483.       {                /* transformation applies to entire image */
  484.       if (IS_CPACK(imgptr))
  485.         {
  486.         modify_rgb(imgptr->raster, imgptr->w * imgptr->h, rgb[0],
  487.                rgb[1], rgb[2]);
  488.         }
  489.       else
  490.         {
  491.         modify_cmap(imgptr->cmap, rgb[0], rgb[1], rgb[2]);
  492.         }
  493.       imgptr->io->display(imgptr, 1, 0);
  494.       }
  495.     else
  496.       {                /* to a specific region */
  497.       modify_rgb(pp[0], rh * rw, rgb[0], rgb[1], rgb[2]);
  498.       put_subimage(imgptr, pp, make_rect(rx, ry, rw, rh), 1);
  499.       set_current_window(win_id);
  500.       Rectwrite(rx, ry, rx + rw - 1, ry + rh - 1, pp[0]);
  501.       free_mat(pp);
  502.       }
  503. }
  504.  
  505. /***************************************************************
  506.  * interpolate and normalize the transformation (x,y) from (0,1)
  507.  * to (0, PCMAXV)
  508.  ***************************************************************/
  509.  
  510. static void
  511. normalize_func(float *x, float *y, int n, pc_t *norm)
  512. {
  513.     int i, k;
  514.     float xx, yy;
  515.  
  516.     for (i = 0; i < PCMAX; i++)
  517.       {
  518.       xx = (double) i / PCMAXV;
  519.       k = b_search(x, n, xx);
  520.  
  521.       if ((x[k + 1] - x[k]) > 1.e-5)
  522.           yy = y[k] + (y[k + 1] - y[k]) / (x[k + 1] - x[k])
  523.           * (xx - x[k]);
  524.       else
  525.           yy = (y[k] + y[k + 1]) * 0.5;
  526.  
  527.       /* force to within (0,1) */
  528.       Range(yy, 0.0, 1.0);
  529.       norm[i] = (yy * PCMAXV + 0.5);
  530.       }
  531. }
  532.  
  533. /******************************************************************
  534.  * apply the transformation defined by fx, fy
  535.  ******************************************************************/
  536.  
  537. /* ARGSUSED */
  538. static void
  539. apply_func(FL_OBJECT * p, long q)
  540. {
  541.     int j;
  542.     pc_t rgb[3][PCMAX];
  543.     void *pp = 0;
  544.     long owin = winget();
  545.  
  546.  
  547.     if (lastswap == -1)        /* identity transformation */
  548.     return;
  549.  
  550.     /* at this point, all changes made so far becomes permanent */
  551.     free_image(saved);
  552.     saved = img_dup(imgptr);
  553.     changed = 1;
  554.  
  555.     pp = check_if_region();
  556.  
  557.     /*
  558.      * if swap/replace pixels, need special handling 'cause the seperated RGB
  559.      * transformation can't do it
  560.      */
  561.  
  562.     show_busy("Transforming ...");
  563.  
  564.     if (lastswap)
  565.       {                /* fake */
  566.       swap_pixels(pp);
  567.       }
  568.     else
  569.       {
  570.       /* general transformation * */
  571.       for (j = 0; j < 3; j++)
  572.         {
  573.         fl_get_xyplot(fcol[j], fx[j], fy[j], lastn + j);
  574.         normalize_func(fx[j], fy[j], lastn[j], rgb[j]);
  575.         }
  576.       do_gen_tran(pp, rgb);
  577.       }
  578.  
  579.     end_busy();
  580.     set_current_window(owin);
  581. }
  582.  
  583. /****************************************************
  584.  *  generate the gamma table
  585.  ****************************************************/
  586.  
  587. #include <math.h>
  588. /* ARGSUSED */
  589. static void
  590. gamma_cb(FL_OBJECT * p, long q)
  591. {
  592.     int i, j;
  593.     float cgamma = fl_get_counter_value(p);
  594.  
  595.     fl_freeze_form(coledit);
  596.     for (j = c0; j < c1; j++)
  597.       {
  598.       for (i = 0; i < lastn[j]; i++)
  599.         {
  600.         fx[j][i] = (float) i / (lastn[j] - 1);
  601.         fy[j][i] = pow(fx[j][i], cgamma);
  602.         }
  603.       fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
  604.       fl_set_xyplot_text(fcol[j], 0.8, 0.92, 0, ftoa(cgamma, 2),
  605.                  0, FL_BLACK, FL_SMALL_FONT, FL_NORMAL_STYLE);
  606.       }
  607.     fl_unfreeze_form(coledit);
  608.     lastswap = 0;
  609. }
  610.  
  611. /****************************************************************
  612.  * photo-inversion function
  613.  *****************************************************************/
  614. static void
  615. invert_it(void)
  616. {
  617.     int i, j;
  618.  
  619.     for (j = c0; j < c1; j++)
  620.       {
  621.       fl_get_xyplot(fcol[j], fx[j], fy[j], &lastn[j]);
  622.       for (i = 0; i < lastn[j]; i++)
  623.         {
  624.         fy[j][i] = 1.0 - fy[j][i];
  625.         }
  626.       fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
  627.       }
  628. }
  629.  
  630. /****************************************************************
  631.  * pixels clustering
  632.  *****************************************************************/
  633. static void
  634. quant_it(void)
  635. {
  636.     int i, j, n;
  637.     double dx, dy, ddx = 1.0 / PCMAXV;
  638.  
  639.     for (j = c0; j < c1; j++)
  640.       {
  641.       /* need to be even number of points */
  642.       lastn[j] += (lastn[j] % 2);
  643.       fl_set_counter_value(ncounter, lastn[j]);
  644.  
  645.       /* divide into segments of half of no. of points */
  646.       n = lastn[j] / 2;
  647.       dx = 1.0 / n;
  648.       dy = 1.0 / (n - 1);
  649.       fx[j][0] = fy[j][0] = 0.0;
  650.       fx[j][lastn[j] - 1] = fy[j][lastn[j] - 1] = 1.0;
  651.  
  652.       for (i = 1; i < lastn[j] - 2; i += 2)
  653.         {
  654.         fx[j][i] = fx[j][i - 1] + dx - ddx;
  655.         fy[j][i] = fy[j][i - 1];
  656.         fx[j][i + 1] = fx[j][i] + ddx + ddx;
  657.         fy[j][i + 1] = fy[j][i] + dy;
  658.         }
  659.       fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
  660.       }
  661. }
  662.  
  663. /*******************************************************
  664.  * Thresholding function
  665.  ********************************************************/
  666. static void
  667. threshold(void)
  668. {
  669.     int j, done;
  670.     static int th = 126;
  671.     double ddx = 1.0 / PCMAXV;
  672.  
  673.     for (j = c0; j < c1; j++)
  674.     lastn[j] = 4;
  675.  
  676.     quant_it();
  677.     do
  678.       {
  679.       for (j = c0; j < c1; j++)
  680.         {
  681.         fx[j][1] = (float) th / PCMAXV;
  682.         fx[j][2] = fx[j][1] + ddx;
  683.         fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
  684.         }
  685.       done = getint("Enter Threshold", &th, 1, 254, 1);
  686.       }
  687.     while (!done);
  688.  
  689.     /* final functions */
  690.     for (j = c0; j < c1; j++)
  691.       {
  692.       fx[j][1] = (float) th / PCMAXV;
  693.       fx[j][2] = fx[j][1] + ddx;
  694.       fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
  695.       }
  696. }
  697.  
  698. /**************************************************************
  699.  * setting clusters of pixels to zero, sort of like contour
  700.  ***************************************************************/
  701. static void
  702. band_it(void)
  703. {
  704.     int i, j, n;
  705.     double dx, dy, ddx = 1.0 / PCMAXV, yy;
  706.  
  707.     /*
  708.      * divide the region into segments with alternating zeros. there must be
  709.      * gurantee that the no. of points is multple of 4 and minimum is 8. (4
  710.      * points band is the same as two step)
  711.      */
  712.  
  713.     for (j = c0; j < c1; j++)
  714.       {
  715.       fl_get_xyplot(fcol[j], fx[j], fy[j], &lastn[j]);
  716.       lastn[j] = 4 * (lastn[j] / 4);
  717.       if (lastn[j] < 8)
  718.           lastn[j] = 8;
  719.       fl_set_counter_value(ncounter, lastn[j]);
  720.  
  721.       /* no. of periods */
  722.       n = lastn[j] / 4;
  723.  
  724.       dx = 1.0 / (2.0 * n);
  725.       dy = 1.0 / n;
  726.  
  727.       /* the stuff within the loop is exactly one period */
  728.       yy = 0.0;
  729.       for (i = 0; i < lastn[j] - 3; i += 4)
  730.         {
  731.  
  732.         fx[j][i] = dx * (i / 2);
  733.         fy[j][i] = 0.0;
  734.         fx[j][i + 1] = fx[j][i] + dx;
  735.         fy[j][i + 1] = 0.0;
  736.  
  737.         fx[j][i + 2] = fx[j][i + 1] + ddx;
  738.         fy[j][i + 2] = (yy += dy);
  739.         fx[j][i + 3] = fx[j][i + 2] + dx - 2.0 * ddx;
  740.         fy[j][i + 3] = yy;
  741.         }
  742.       fx[j][lastn[j] - 1] = 1.0;
  743.       fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
  744.       }
  745. }
  746.  
  747.  
  748. /*******************************************************************
  749.  * This function shows the approximate transformation function,
  750.  * but it really does not do anything useful since replace and swap are
  751.  * handled seperately by table pswtbl, not by reading and digitizing
  752.  * the functions
  753.  *********************************************************************/
  754. static void
  755. fake_1(float *x, float *y, int n, int from, int to)
  756. {
  757.     int i;
  758.  
  759.     i = b_search(x, n, (float) from / PCMAXV);
  760.     if (i == 0)
  761.       {
  762.       x[i] = (float) from / PCMAXV;
  763.       y[i] = (float) to / PCMAXV;
  764.       x[i + 1] = (float) (from + 0.9) / PCMAXV;
  765.       y[i + 1] = x[i + 1];
  766.       }
  767.     else
  768.       {
  769.       x[i] = (float) from / PCMAXV;
  770.       y[i] = (float) to / PCMAXV;
  771.  
  772.       x[i - 1] = (float) (from - 0.9) / PCMAXV;
  773.       y[i - 1] = x[i - 1];
  774.       if (i < n - 1)
  775.         {
  776.         x[i + 1] = (float) (from + 0.9) / PCMAXV;
  777.         y[i + 1] = x[i - 1];
  778.         }
  779.       }
  780. }
  781.  
  782. /**********************************************/
  783. static void
  784. fake_func(int sw)
  785. {
  786.     int i, j;
  787.  
  788.     /* 8 or 9 points should be enough, even for swapping */
  789.     if (lastn[0] < 9)
  790.     lastn[0] = lastn[1] = lastn[2] = 9;
  791.  
  792.     /* initialize to identity transformation */
  793.     for (j = 0; j < 3; j++)
  794.       {
  795.       for (i = 0; i < lastn[j]; i++)
  796.           fx[j][i] = fy[j][i] = (float) i / (lastn[j] - 1);
  797.       }
  798.  
  799.     /* check to see if operation is an identity */
  800.     for (i = j = 0; !j && i < 3; i++)
  801.     j = (pswtbl[0][i] - pswtbl[1][i]);
  802.     if (!j)
  803.     return;
  804.  
  805.     fl_clear_xyplot_text(fcol[0]);
  806.     fl_clear_xyplot_text(fcol[1]);
  807.     fl_clear_xyplot_text(fcol[2]);
  808.  
  809.     fl_freeze_form(coledit);
  810.  
  811.     /* generate the function */
  812.     fl_add_xyplot_text(fcol[0], 0.6, 0.92, 0, sw ? "SwapPix" : "ChangePix",
  813.                0, FL_BLACK, FL_SMALL_FONT, FL_NORMAL_STYLE);
  814.     for (j = 0; j < 3; j++)
  815.       {
  816.  
  817.       fake_1(fx[j], fy[j], lastn[j], pswtbl[0][j], pswtbl[1][j]);
  818.       if (sw)
  819.           fake_1(fx[j], fy[j], lastn[j], pswtbl[1][j], pswtbl[0][j]);
  820.       fl_set_xyplot_only(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
  821.       }
  822.     fl_set_counter_value(ncounter, Max(lastn[0], lastn[2]));
  823.     fl_unfreeze_form(coledit);
  824. }
  825.  
  826. /******************************************************************
  827.  * Pixel transformation routines
  828.  ******************************************************************/
  829. static void show_pix2(int);
  830.  
  831. static void
  832. pix_swap(void)
  833. {
  834.     lastswap = 2;
  835.     show_pix2(1);
  836. }
  837.  
  838. static void
  839. pix_replace(void)
  840. {
  841.     lastswap = 1;
  842.     show_pix2(0);
  843. }
  844.  
  845. static void
  846. shift_it(int dir)
  847. {
  848.     int i, j, iy;
  849.  
  850.     for (j = c0; j < c1; j++)
  851.       {
  852.       fl_get_xyplot(fcol[j], fx[j], fy[j], &lastn[j]);
  853.       for (i = 0; i < lastn[j]; i++)
  854.         {
  855.         iy = (fy[j][i] * (PCMAX - 1) + 0.5);
  856.         iy = (dir > 0 ? (iy << 1) : (iy >> 1));
  857.         iy &= PCMAX - 1;
  858.         fy[j][i] = (float) iy / (PCMAX - 1);
  859.         }
  860.       fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
  861.       }
  862. }
  863.  
  864. static void
  865. dn_shift(void)
  866. {
  867.     shift_it(-1);
  868. }
  869.  
  870. static void
  871. up_shift(void)
  872. {
  873.     shift_it(1);
  874. }
  875.  
  876. /* do a f(x) = log(1.0+ scale * x)/log(scale + 1) */
  877. static void
  878. detail_it(void)
  879. {
  880.     int i, j;
  881.     static float dscale = 5.0;
  882.     double factor;
  883.     int done;
  884.  
  885.     do
  886.       {
  887.       factor = 1.0 / log10(1.0 + dscale);
  888.       for (j = c0; j < c1; j++)
  889.         {
  890.         for (i = 0; i < lastn[j]; i++)
  891.           {
  892.               fy[j][i] = log10(dscale * fx[j][i] + 1.0) * factor;
  893.           }
  894.         fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
  895.         }
  896.       done = getfloat("Enter Scale factor:", &dscale, 1.0, 100.0, 1, 1);
  897.       }
  898.     while (!done);
  899. }
  900.  
  901. /*************************************************************
  902.  * Dark darker, bright brighter
  903.  *
  904.  * To get the correct curvature, we need to invert the
  905.  * following function and the inversion is not unique or
  906.  * out of the real domain, do it numerically, taking advantage
  907.  * of the fact the inversion is just a mirror at y = x
  908.  **************************************************************/
  909. #define F(x)  (0.5 * ( 1.0 + pow(2.0*(x)-1,3.0)))
  910. static void
  911. dd_bb(void)
  912. {
  913.     int i, j;
  914.     for (j = c0; j < c1; j++)
  915.       {
  916.       for (i = 0; i < lastn[j]; i++)
  917.         {
  918.         fy[j][i] = (float) i / (lastn[j] - 1);
  919.         fx[j][i] = F(fy[j][i]);
  920.         }
  921.       fl_set_xyplot(fcol[j], fx[j], fy[j], lastn[j], "", xl, yl);
  922.       }
  923. }
  924.  
  925.  
  926.  
  927. /* brightness of the image */
  928. static int bpercent = 1;
  929. /* ARGSUSED */
  930. static void
  931. bset_cb(FL_OBJECT * q, long p)
  932. {
  933.     bpercent = !bpercent;
  934.     fl_set_object_label(q, bpercent ? "Brightness(%)" : "Brightness(Abs)");
  935. }
  936.  
  937. /* ARGSUSED */
  938. static void
  939. brightness_cb(FL_OBJECT * q, long p)
  940. {
  941.     int i, j;
  942.     float delta = 0.01;
  943.     float *x, *y;
  944.  
  945.     delta = 0.01 * p;
  946.     for (j = c0; j < c1; j++)
  947.       {
  948.       x = fx[j];
  949.       y = fy[j];
  950.       fl_get_xyplot(fcol[j], x, y, &lastn[j]);
  951.       if (bpercent)
  952.         {            /* percentge */
  953.         for (i = 0; i < lastn[j]; i++)
  954.           {
  955.               y[i] *= (1.0 + delta);
  956.               if (y[i] > 1.0)
  957.               y[i] = 1.0;
  958.           }
  959.         }
  960.       else
  961.         {            /* abslute change */
  962.         for (i = 0; i < lastn[j]; i++)
  963.           {
  964.               y[i] += delta;
  965.               if (y[i] < 0.0)
  966.               y[i] = 0.0;
  967.               else if (y[i] > 1.0)
  968.               y[i] = 1.0;
  969.           }
  970.         }
  971.       fl_set_xyplot(fcol[j], x, y, lastn[j], "", xl, yl);
  972.       fl_set_xyplot_ybounds(fcol[j], 0.0, 1.0);
  973.       }
  974.     lastswap = 0;
  975. }
  976.  
  977. /*ARGSUSED*/
  978. static int
  979. init_pixtran(IPTR im, int wme)
  980. {
  981.     static int irx, iry;
  982.  
  983.     set_rubber_bounds(1, im->xi, im->yi, im->w, im->h);
  984.  
  985.     if (wme)
  986.       {
  987.       rx += im->xi - irx;
  988.       ry += im->yi - iry;
  989.       }
  990.     else
  991.       {
  992.       rw = im->w;
  993.       rh = im->h;
  994.       rx = im->xi;
  995.       ry = im->yi;
  996.       }
  997.     irx = im->xi;
  998.     iry = im->yi;
  999.     return 0;
  1000. }
  1001.  
  1002.  
  1003. /* ARGSUSED */
  1004. static void
  1005. undo_cb(FL_OBJECT * q, long p)
  1006. {
  1007.     if (!changed)
  1008.     return;
  1009.     free_image(imgptr);
  1010.     imgptr = img_dup(saved);
  1011.     imgptr->io->display(imgptr, 0, 0);
  1012.     end_busy();
  1013.     changed = 0;
  1014. }
  1015.  
  1016. /* done */
  1017. /* ARGSUSED */
  1018. static void
  1019. finish_coledit(FL_OBJECT * p, long q)
  1020. {
  1021.     remove_wm_handler(init_pixtran);
  1022.     fl_qenter(KEYBD, 27);
  1023. }
  1024.  
  1025. static void
  1026. create_form_coledit(void)
  1027. {
  1028.     FL_OBJECT *obj;
  1029.     int i, totalsc = sizeof(sc) / sizeof(sc[0]);
  1030.     float y, dy, x, dx;
  1031.     static int ok;
  1032.  
  1033.     if (ok)
  1034.     return;
  1035.     coledit = fl_bgn_form(FL_NO_BOX, 380.0, 470.0);
  1036.     obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 380.0, 470.0, "");
  1037.     fl_set_object_color(obj, 9, 47);
  1038.     fl_set_object_align(obj, FL_ALIGN_TOP);
  1039.     obj = fl_add_button(FL_HIDDEN_BUTTON, 0, 0, 380, 470, "");
  1040.     fl_set_call_back(obj, help_cb, HELP_COLEDIT);
  1041.  
  1042.     /* transformation functions */
  1043.     tranfg = fl_bgn_group();
  1044.     y = 310;
  1045.     dy = 150;
  1046.     for (i = 0; i < 3; i++, y -= dy)
  1047.       {
  1048.       fcol[i] = fl_add_xyplot(FL_ACTIVE_XYPLOT, 10.0, y, 170.0, dy, "");
  1049.       fl_set_xyplot_xscale(fcol[i], 0, 0);
  1050.       fl_set_xyplot_yscale(fcol[i], 0, 0);
  1051.       fl_set_xyplot_return(fcol[i], 1);
  1052.       fl_set_object_color(fcol[i], 9, 9);
  1053.       fl_set_xyplot_autobounds(fcol[i], 0, 0);
  1054.       fl_set_xyplot_xbounds(fcol[i], 0.0, 1.0);
  1055.       fl_set_xyplot_ybounds(fcol[i], 0.0, 1.0);
  1056.       fl_set_call_back(fcol[i], show_it, i);
  1057.       }
  1058.     fl_set_xyplot_colors(fcol[0], FL_RED, 0);
  1059.     fl_set_xyplot_colors(fcol[1], FL_GREEN, 0);
  1060.     fl_set_xyplot_colors(fcol[2], FL_BLUE, 0);
  1061.     fl_end_group();
  1062.  
  1063.  
  1064.     /* gamma */
  1065.     gm = fl_add_counter(FL_NORMAL_COUNTER, 200.0, 90.0, 160.0, 25.0, "Gamma");
  1066.     fl_set_object_lsize(gm, 10.0);
  1067.     fl_set_object_align(gm, FL_ALIGN_TOP);
  1068.     fl_set_counter_precision(gm, 2);
  1069.     fl_set_counter_bounds(gm, 0.001, 10);
  1070.     fl_set_counter_step(gm, 0.05, 0.20);
  1071.     fl_set_counter_value(gm, 1.0);
  1072.     fl_set_counter_return(gm, 1);
  1073.     fl_set_call_back(gm, gamma_cb, 0);
  1074.  
  1075.     /* brightness */
  1076.     obj = fl_add_button(FL_TOUCH_BUTTON, 210.0, 40.0, 25.0, 25.0, "<<");
  1077.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1078.     fl_set_object_color(obj, 47, 12);
  1079.     fl_set_call_back(obj, brightness_cb, -3);
  1080.     obj = fl_add_button(FL_TOUCH_BUTTON, 235.0, 40.0, 25.0, 25.0, "<");
  1081.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1082.     fl_set_object_color(obj, 47, 12);
  1083.     fl_set_call_back(obj, brightness_cb, -1);
  1084.     obj = fl_add_button(FL_TOUCH_BUTTON, 330.0, 40.0, 25.0, 25.0, ">>");
  1085.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1086.     fl_set_object_color(obj, 47, 12);
  1087.     fl_set_call_back(obj, brightness_cb, 3);
  1088.     obj = fl_add_button(FL_TOUCH_BUTTON, 305.0, 40.0, 25.0, 25.0, ">");
  1089.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1090.     fl_set_object_color(obj, 47, 12);
  1091.     fl_set_call_back(obj, brightness_cb, 1);
  1092.     obj = fl_add_button(FL_NB, 230.0, 65.0, 110.0, 20.0, "");
  1093.     fl_set_object_label(obj, bpercent ? "Brightness(%)" : "Brightness(Abs)");
  1094.     fl_set_object_boxtype(obj, FL_FLAT_BOX);
  1095.     fl_set_object_lsize(obj, 10.0);
  1096.     fl_set_object_color(obj, 9, 9);
  1097.     fl_set_call_back(obj, bset_cb, 0);
  1098.  
  1099.     /* color apply group */
  1100.     fl_bgn_group();
  1101.     app[0] = obj = fl_add_roundbutton(FL_RB, 195.0, 430.0, 30.0, 30.0, "Red");
  1102.     fl_set_object_color(obj, 7, 1);
  1103.     fl_set_object_lsize(obj, 10.0);
  1104.     fl_set_call_back(obj, cind_cb, 0);
  1105.     app[1] = obj = fl_add_roundbutton(FL_RB, 250.0, 430.0, 30.0, 30.0, "Green");
  1106.     fl_set_object_color(obj, 7, 2);
  1107.     fl_set_object_lsize(obj, 10.0);
  1108.     fl_set_call_back(obj, cind_cb, 1);
  1109.     app[2] = obj = fl_add_roundbutton(FL_RB, 320.0, 430.0, 30.0, 30.0, "Blue");
  1110.     fl_set_object_color(obj, 7, 4);
  1111.     fl_set_object_lsize(obj, 10.0);
  1112.     fl_set_call_back(obj, cind_cb, 2);
  1113.     app[3] = obj = fl_add_button(FL_RB, 235.0, 405.0, 115.0, 25.0, "RGB");
  1114.     fl_set_object_lsize(obj, 10.0);
  1115.     fl_set_object_color(obj, FL_MAGIC1, FL_MAGIC2);
  1116.     fl_set_call_back(obj, cind_cb, 3);
  1117.     c0 = 0;
  1118.     c1 = 3;
  1119.     fl_set_button(obj, 1);
  1120.     fl_end_group();
  1121.  
  1122.     ncounter = obj = fl_add_counter(FL_NC, 210.0, 360.0, 160.0, 25.0,
  1123.                     "Control Points");
  1124.     fl_set_object_lsize(obj, 10.0);
  1125.     fl_set_object_align(obj, FL_ALIGN_TOP);
  1126.     fl_set_counter_precision(obj, 0);
  1127.     fl_set_counter_bounds(obj, MINPNTS, MAXPNTS);
  1128.     fl_set_counter_step(obj, 1, 2);
  1129.     fl_set_counter_value(obj, lastn[0]);
  1130.     fl_set_counter_return(obj, 1);
  1131.     fl_set_call_back(obj, pnts_cb, 0);
  1132.  
  1133.     /* misc control  */
  1134.     obj = fl_add_button(FL_NORMAL_BUTTON, 280.0, 145.0, 80.0, 25.0, "Apply");
  1135.     fl_set_object_color(obj, 47, 3);
  1136.     fl_set_object_lsize(obj, 10.00);
  1137.     fl_set_call_back(obj, apply_func, 0);
  1138.     obj = fl_add_button(FL_NORMAL_BUTTON, 200.0, 145.0, 80.0, 25.0, "Undo");
  1139.     fl_set_object_color(obj, FL_MAGIC1, FL_GREEN);
  1140.     fl_set_object_lsize(obj, 10.0);
  1141.     fl_set_call_back(obj, undo_cb, 0);
  1142.  
  1143.     obj = fl_add_button(FL_NORMAL_BUTTON, 310.0, 10.0, 60.0, 25.0, "Done");
  1144.     fl_set_object_lsize(obj, 10.0);
  1145.     fl_set_object_color(obj, FL_MAGIC1, FL_YELLOW);
  1146.     fl_set_call_back(obj, finish_coledit, 0);
  1147.  
  1148.     /* short cuts */
  1149.     y = 320.0;
  1150.     x = 200.0;
  1151.     for (dx = 80, dy = 25, i = 0; i < totalsc; i += 2, y -= dy)
  1152.       {
  1153.       obj = fl_add_button(FL_NB, x, y, dx, dy, sc[i].l);
  1154.       fl_set_object_lsize(obj, 10.0);
  1155.       fl_set_object_color(obj, FL_MAGIC1, sc[i].col);
  1156.       fl_set_call_back(obj, do_short_cuts, i);
  1157.       if (i + 1 < totalsc)
  1158.         {
  1159.         obj = fl_add_button(FL_NB, x + dx + 5, y, dx, dy, sc[i + 1].l);
  1160.         fl_set_object_lsize(obj, 10.0);
  1161.         fl_set_object_color(obj, FL_MAGIC1, sc[i + 1].col);
  1162.         fl_set_call_back(obj, do_short_cuts, i + 1);
  1163.         }
  1164.       }
  1165.     fl_end_form();
  1166.     ok = 1;
  1167.     init_func();
  1168. }
  1169.  
  1170. /*******************************************************************
  1171.  * Pixel Swap and Pixel Change Routines
  1172.  *
  1173.  ******************************************************************/
  1174. static FL_FORM *pix2;        /* pixel swap/replace form */
  1175. static FL_OBJECT *plab[2], *colbox[2];
  1176. static void create_form_pix2(void);
  1177.  
  1178. /* showing the swap/change colors: FORM index */
  1179. static int pcind[2] =
  1180. {
  1181.     1038, 1039
  1182. };
  1183.  
  1184. /************************************************************
  1185.  * present the colors in pixelswap in RGB components and
  1186.  * also redraw the colorbox showing the packed color
  1187.  *******************************************************/
  1188. static int whichC;
  1189. static void
  1190. show_label(int ccc[])
  1191. {
  1192.     char pt[100];
  1193.  
  1194.     sprintf(pt, "(%d,%d,%d)", ccc[0], ccc[1], ccc[2]);
  1195.     fl_freeze_form(pix2);
  1196.     fl_set_object_label(plab[whichC], pt);
  1197.     fl_mapcolor(pcind[whichC], ccc[0], ccc[1], ccc[2]);
  1198.     fl_redraw_object(colbox[whichC]);
  1199.     fl_unfreeze_form(pix2);
  1200.     fake_func(lastswap - 1);
  1201. }
  1202.  
  1203. /******** Set either the target or new pix *********/
  1204. /*ARGSUSED*/
  1205. static void
  1206. setpix(FL_OBJECT * q, long p)
  1207. {
  1208.     whichC = p;
  1209.     set_getcolor_cb(show_label);
  1210.     get_color(imgptr, pswtbl[p], 0);
  1211. }
  1212.  
  1213. /********* Targe/new pixels are selected *********/
  1214. /*ARGSUSED*/
  1215. static void
  1216. pix2_done(FL_OBJECT * p, long q)
  1217. {
  1218.     if (pix2 && pix2->visible)
  1219.       {
  1220.       hide_getcolor();
  1221.       bit_hide_form(pix2);
  1222.       fake_func(lastswap - 1);
  1223.       }
  1224. }
  1225.  
  1226. static FL_OBJECT *bi;
  1227.  
  1228. static void
  1229. show_pix2(int sw)
  1230. {
  1231.     create_form_pix2();
  1232.     (sw ? fl_show_object : fl_hide_object) (bi);
  1233.     bit_show_form(pix2, FL_PLACE_SIZE, 0, "Pixel2");
  1234. }
  1235.  
  1236. static void
  1237. create_form_pix2(void)
  1238. {
  1239.     FL_OBJECT *obj;
  1240.     static int pix2form;
  1241.  
  1242.     if (pix2form)
  1243.     return;
  1244.     pix2 = fl_bgn_form(FL_NO_BOX, 310.0, 170.0);
  1245.     obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 310.0, 170.0, "");
  1246.     obj = fl_add_button(FL_NB, 15.0, 120.0, 85.0, 30.0, "SetTarget");
  1247.     fl_set_object_lsize(obj, 10.0);
  1248.     fl_set_call_back(obj, setpix, 0);
  1249.     obj = fl_add_button(FL_NB, 15.0, 50.0, 85.0, 30.0, "SetNewPix");
  1250.     fl_set_object_lsize(obj, 10.0);
  1251.     fl_set_call_back(obj, setpix, 1);
  1252.     colbox[0] = obj = fl_add_box(FL_DOWN_BOX, 220.0, 120.0, 80.0, 30.0, "");
  1253.     fl_mapcolor(pcind[0], pswtbl[0][0], pswtbl[0][1], pswtbl[0][2]);
  1254.     fl_set_object_color(obj, pcind[0], 0);
  1255.     colbox[1] = obj = fl_add_box(FL_DOWN_BOX, 220.0, 50.0, 80.0, 30.0, "");
  1256.     fl_mapcolor(pcind[1], pswtbl[1][0], pswtbl[1][1], pswtbl[1][2]);
  1257.     fl_set_object_color(obj, pcind[1], 0);
  1258.     plab[0] = obj = fl_add_text(FL_NT, 110.0, 120.0, 100.0, 30.0, "");
  1259.     fl_set_object_boxtype(obj, FL_BORDER_BOX);
  1260.     fl_set_object_lsize(obj, 10.0);
  1261.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  1262.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  1263.     plab[1] = obj = fl_add_text(FL_NT, 110.0, 50.0, 100.0, 30.0, "");
  1264.     fl_set_object_boxtype(obj, FL_BORDER_BOX);
  1265.     fl_set_object_lsize(obj, 10.0);
  1266.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  1267.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  1268.     obj = fl_add_button(FL_RETURN_BUTTON, 120.0, 10.0, 80.0, 30.0, "OK");
  1269.     fl_set_object_color(obj, 47, 2);
  1270.     fl_set_object_lsize(obj, 10.0);
  1271.     fl_set_call_back(obj, pix2_done, 0);
  1272.     obj = fl_add_box(FL_FLAT_BOX, 110.0, 80.0, 40.0, 40.0, "@2");
  1273.     fl_set_object_lcol(obj, 4);
  1274.     bi = obj = fl_add_box(FL_FLAT_BOX, 160.0, 80.0, 40.0, 40.0, "@8");
  1275.     fl_set_object_lcol(obj, 4);
  1276.     fl_end_form();
  1277.     pix2form = 1;
  1278.     show_label(pswtbl[whichC = 0]);
  1279.     show_label(pswtbl[whichC = 1]);
  1280. }
  1281.  
  1282. /************************************End of 1 to 1 ***** }*/
  1283.  
  1284. /*---- call back routines when there is color change ----*/
  1285.  
  1286. static Getcolor_cb color_cb, rgbcolor_cb, cmapcolor_cb;
  1287. static GLQhandler color_glcb, rgbcolor_glcb, cmapcolor_glcb;
  1288.  
  1289. /* alter the current color */
  1290. static void (*set_current_color) (int[]);
  1291.  
  1292. /**************** local functions ******************************/
  1293.  
  1294. static void create_the_forms(void);
  1295. static void hide_rgb_form(void);
  1296. static void hide_cmap_form(void);
  1297. static void set_rgbcolor(int[]);
  1298. static void set_cmapcolor(int[]);
  1299.  
  1300. /*******************************************************************
  1301.  * the global routines that get called to handle color selection
  1302.  *
  1303.  *   get_color
  1304.  *   hide_getcolor
  1305.  *   set_getcolor_cb
  1306.  *   set_getcolor_glcb
  1307.  *   set_getcolor
  1308.  *
  1309.  * All routines are image type blind
  1310.  ****************************************************************{*/
  1311.  
  1312. /*******************************************************
  1313.  * Global entry
  1314.  ******************************************************/
  1315. int
  1316. get_color(IPTR im, int col[], int block)
  1317. {
  1318.     int status;
  1319.  
  1320.     create_the_forms();
  1321.     if (IS_CI(im))
  1322.       {
  1323.       int ci;
  1324.  
  1325.       /* default handlers */
  1326.       cmapcolor_cb = color_cb;
  1327.       cmapcolor_glcb = color_glcb;
  1328.  
  1329.       status = get_cmapcolor(im, col, block);
  1330.       ci = col[3];
  1331.       col[0] = im->cmap->ct[0][ci];
  1332.       col[1] = im->cmap->ct[1][ci];
  1333.       col[2] = im->cmap->ct[2][ci];
  1334.       }
  1335.     else
  1336.       {
  1337.       /* default handlers */
  1338.       rgbcolor_cb = color_cb;
  1339.       rgbcolor_glcb = color_glcb;
  1340.  
  1341.       status = get_RGBcolor(im, col, block);
  1342.       col[3] = 0;
  1343.       }
  1344.  
  1345.     /* remove the handlers */
  1346.     color_cb = 0;
  1347.     color_glcb = 0;
  1348.     set_current_color = 0;
  1349.     return status;
  1350. }
  1351.  
  1352.  
  1353. /* remove the get color control panel */
  1354. void
  1355. hide_getcolor(void)
  1356. {
  1357.     create_the_forms();
  1358.     hide_rgb_form();
  1359.     hide_cmap_form();
  1360. }
  1361.  
  1362. /* alter whatever is selected in the color selection panel */
  1363. void
  1364. set_getcolor(int c[])
  1365. {
  1366.     if (set_current_color)
  1367.     set_current_color(c);
  1368. }
  1369.  
  1370. /****************************************************************
  1371.  * function to handle color changes
  1372.  ****************************************************************/
  1373. void
  1374. set_getcolor_cb(Getcolor_cb cb)
  1375. {
  1376.     color_cb = cb;
  1377. }
  1378.  
  1379. /******************************************************************
  1380.  * functions to handle Q events. Not impleneted and untested
  1381.  ******************************************************************/
  1382. void
  1383. set_getcolor_glcb(GLQhandler cb)
  1384. {
  1385.     color_glcb = cb;
  1386. }
  1387.  
  1388.  
  1389. /********************************************************************
  1390.  *
  1391.  * END OF color selection
  1392.  *******************************************************************}*/
  1393.  
  1394. /********************************************************************
  1395.  * Select a particular color in RGB
  1396.  ****************************************************************{*/
  1397.  
  1398. /*-------- local functions ----------------------- */
  1399. static void slider_cb(FL_OBJECT *, long);
  1400. static void create_the_forms(void);
  1401.  
  1402. /*---------local variables -------------------------*/
  1403.  
  1404. static int rgbcol[4];        /* buffer, used on cancel          */
  1405. static int *ccrgb;        /* arrays as passed to get_RGBcolor */
  1406.  
  1407. /* GUI variables */
  1408. static FL_FORM *rgb_form;
  1409. static FL_FORM *predefc;    /* forms for PreDefinedColors */
  1410. static FL_OBJECT *ok_butt, *slider[3], *cancel;
  1411. static FL_OBJECT *pcc;
  1412. static int rgb_border = 1;
  1413.  
  1414. /* to avoid interference with window manager or bit program
  1415.  * use something large as the button colors
  1416.  */
  1417. #define OK_I         (MAXCML + 10)
  1418. #define CAN_I        (MAXCML + 11)
  1419.  
  1420.  
  1421. /**************************************************************
  1422.  * Change the RGB color. All RGB color setting for the mixer
  1423.  * Must go thru this
  1424.  *************************************************************/
  1425. static void
  1426. set_rgb_slider(int s1, int s2, int s3)
  1427. {
  1428.     int cr, cg, cb;
  1429.  
  1430.     fl_freeze_form(rgb_form);
  1431.  
  1432.     /* getting a slider is much faster than setting a slider */
  1433.     cr = fl_get_slider_value(slider[0]);
  1434.     cg = fl_get_slider_value(slider[1]);
  1435.     cb = fl_get_slider_value(slider[2]);
  1436.  
  1437.     /* change only the sliders that need to be changed */
  1438.     if (cr - s1)
  1439.     fl_set_slider_value(slider[0], s1);
  1440.     if (cg - s2)
  1441.     fl_set_slider_value(slider[1], s2);
  1442.     if (cb - s3)
  1443.     fl_set_slider_value(slider[2], s3);
  1444.  
  1445.     /* show current selection */
  1446.     fl_mapcolor(OK_I, s1, s2, s3);
  1447.     fl_redraw_object(ok_butt);
  1448.     fl_unfreeze_form(rgb_form);
  1449.  
  1450.     /* cache and also taking care of input ccrgb is an alias */
  1451.     if (ccrgb)
  1452.       {
  1453.       ccrgb[0] = s1;
  1454.       ccrgb[1] = s2;
  1455.       ccrgb[2] = s3;
  1456.       }
  1457.  
  1458. }
  1459.  
  1460. static int namedcolor;        /* if current color is named */
  1461. /* invoked by set_getcolor */
  1462. static void
  1463. set_rgbcolor(int c[])
  1464. {
  1465.     set_rgb_slider(c[0], c[1], c[2]);
  1466.  
  1467.     /* color setting invalidates predefined color names */
  1468.     if (namedcolor)
  1469.       {
  1470.       fl_deselect_browser(pcc);
  1471.       namedcolor = 0;
  1472.       }
  1473.  
  1474.     /* also need to service the color change */
  1475.     if (rgbcolor_cb)
  1476.     rgbcolor_cb(c);
  1477. }
  1478.  
  1479. /* draw the cancel button as the input color */
  1480. static void
  1481. draw_rgb_cancel(int col[])
  1482. {
  1483.     fl_mapcolor(CAN_I, col[0], col[1], col[2]);
  1484.     fl_redraw_object(cancel);
  1485. }
  1486.  
  1487. /**********************************************************
  1488.  * Handle GL events that occur. If the events are known
  1489.  * and handled, return 0, else return the input event
  1490.  *********************************************************/
  1491.  
  1492. /***********************************************
  1493.  * How to pick a screen pixel as current color
  1494.  **********************************************/
  1495.  
  1496. /*ARGSUSED*/
  1497. static long
  1498. rgb_pick_pix(long dev, short val)
  1499. {
  1500.     int xx, yy, lxx = -1, lyy = -1;
  1501.     rgba_t pixel;
  1502.     int rgb[3];
  1503.  
  1504.     do
  1505.       {
  1506.       /* get mouse position relative to window */
  1507.       WHERE_R2W(xx, yy, win_xo, win_yo);
  1508.       if (xx != lxx || yy != lyy)
  1509.         {
  1510.         lxx = xx;
  1511.         lyy = yy;
  1512.         show_mouse_position(xx, yy);
  1513.         lrectread(xx, yy, xx, yy, &pixel);
  1514.         Unpack(pixel, rgb[0], rgb[1], rgb[2]);
  1515.         set_rgbcolor(rgb);
  1516.         slider_cb(0, 0);
  1517.         }
  1518.       }
  1519.     while (control_down && mouse_down);
  1520.     fl_qreset();
  1521.     return 0;
  1522. }
  1523.  
  1524. /**************************************************
  1525.  * GL event handler while doing color mixing
  1526.  **************************************************/
  1527. static long
  1528. rgb_fl_event(long dev, short val)
  1529. {
  1530.     long cq = dev;
  1531.  
  1532.     /* if not meant for this routine,return the event */
  1533.  
  1534.     if (!rgb_form || !rgb_form->visible)
  1535.     return dev;
  1536.  
  1537.     switch (dev)
  1538.       {
  1539.       case LEFTMOUSE:
  1540.       case MIDDLEMOUSE:
  1541.       if (val && control_down)
  1542.         {
  1543.         cq = rgb_pick_pix(dev, val);
  1544.         }
  1545.       break;
  1546.       case LEFTCTRLKEY:
  1547.       case RIGHTCTRLKEY:
  1548.       if (val)
  1549.         {
  1550.         set_cursor(win_id, CUR_S_CROSS);
  1551.         do
  1552.           {
  1553.               if (getbutton(LEFTMOUSE))
  1554.               cq = rgb_pick_pix(dev, val);
  1555.           }
  1556.         while (control_down);
  1557.         /* control is released, reset cursor */
  1558.         reset_cursor(win_id);
  1559.         cq = 0;
  1560.         }
  1561.       break;
  1562.       }
  1563.     if (cq)            /* still not consumed */
  1564.     cq = rgbcolor_glcb ? rgbcolor_glcb(dev, val) : dev;
  1565.     return cq;
  1566. }
  1567.  
  1568. /***************************************************************
  1569.  * Gloabl entry point for selecting RGB color
  1570.  *
  1571.  ****************************************************************/
  1572.  
  1573. /*ARGSUSED*/
  1574. int
  1575. get_RGBcolor(IPTR im, int col[], int block)
  1576. {
  1577.     int place = block ? FL_PLACE_MOUSE : FL_PLACE_SIZE;
  1578.  
  1579.     create_the_forms();
  1580.  
  1581.     set_current_color = set_rgbcolor;
  1582.  
  1583.     ccrgb = col;
  1584.     set_rgb_slider(col[0], col[1], col[2]);
  1585.  
  1586.     /* make a copy, which will be the cancel color */
  1587.     rgbcol[0] = col[0];
  1588.     rgbcol[1] = col[1];
  1589.     rgbcol[2] = col[2];
  1590.     draw_rgb_cancel(rgbcol);
  1591.  
  1592.  
  1593.     if (!rgb_form->visible)
  1594.       {
  1595.  
  1596.       /* how to handle Q events */
  1597.       install_GLQ_handler(rgb_fl_event);
  1598.       }
  1599.  
  1600.     if (block)
  1601.     fl_deactivate_all_forms();
  1602.  
  1603.     bit_show_form(rgb_form, place, rgb_border, "RGBColor");
  1604.  
  1605.     set_cursor(rgb_form->window, CUR_HAND);
  1606.  
  1607.     if (block)
  1608.       {
  1609.       /* eat every Q events except rgb_fl_event */
  1610.       int rgbfinish;
  1611.       short val;
  1612.       do
  1613.         {
  1614.         rgbfinish = (fl_do_forms() == FL_EVENT) &&
  1615.             (bit_qread(&val) == F1KEY && val == 100);
  1616.         }
  1617.       while (!rgbfinish);
  1618.       fl_activate_all_forms();
  1619.       }
  1620.     return 0;
  1621. }
  1622.  
  1623. /***********************************************************
  1624.  * Remove the mixer and its friends when OK is pressed
  1625.  ***********************************************************/
  1626. /* ARGSUSED */
  1627. static void
  1628. ok_cb(FL_OBJECT * ob, long q)
  1629. {
  1630.     reset_cursor(win_id);
  1631.     fl_activate_all_forms();
  1632.  
  1633.     /* reset all call back functions */
  1634.     rgbcolor_cb = 0;
  1635.     rgbcolor_glcb = 0;
  1636.     remove_GLQ_handler(rgb_fl_event);
  1637.  
  1638.     bit_hide_form(rgb_form);
  1639.     bit_hide_form(predefc);
  1640.  
  1641.     /* secrete terminating key */
  1642.     qenter(F1KEY, 100);
  1643. }
  1644.  
  1645. static void
  1646. hide_rgb_form(void)
  1647. {
  1648.     create_the_forms();
  1649.     if (rgb_form->visible)
  1650.     ok_cb(0, 0);
  1651. }
  1652.  
  1653. /****************************************************************
  1654.  * if cancel is pressed
  1655.  *****************************************************************/
  1656. /*ARGSUSED*/
  1657. static void
  1658. cancel_cb(FL_OBJECT * ob, long q)
  1659. {
  1660.     set_rgb_slider(rgbcol[0], rgbcol[1], rgbcol[2]);
  1661.  
  1662.     /* redraw OK button etc. and re-read slider and service color change  */
  1663.     slider_cb(0, 0);
  1664. }
  1665.  
  1666. /******************************************************************
  1667.  * If there is any change in slider this routine be called
  1668.  * It might also be called by other rouines (which calls
  1669.  * with p == 0
  1670.  *******************************************************************/
  1671. /* ARGSUSED */
  1672. static void
  1673. slider_cb(FL_OBJECT * p, long n)
  1674. {
  1675.     if (p)
  1676.     ccrgb[n] = fl_get_slider_value(slider[n]);
  1677.  
  1678.     fl_mapcolor(OK_I, ccrgb[0], ccrgb[1], ccrgb[2]);
  1679.  
  1680.     fl_redraw_object(ok_butt);
  1681.     if (rgbcolor_cb)
  1682.       {
  1683.       rgbcolor_cb(ccrgb);
  1684.       }
  1685. }
  1686.  
  1687. /****************************************************************
  1688.  * Pre-defined named colors, mainly from /usr/lib/X11/rgb.txt
  1689.  *
  1690.  ***************************************************************/
  1691.  
  1692. #ifndef RGBTEXT
  1693. #define RGBTEXT  "/usr/lib/X11/rgb.txt"
  1694. #endif
  1695.  
  1696. typedef struct
  1697. {
  1698.     int r, g, b;
  1699. }
  1700. rgbtriple;
  1701.  
  1702. /* MAXRGB should not exceed FL_BROWSER_MAXLINE, default 512 */
  1703.  
  1704. #define MAXRGB   450
  1705.  
  1706. /* make sure it does not happen */
  1707. #if (MAXRGB > FL_BROWSER_MAXLINE)
  1708. #undef MAXRGB
  1709. #define MAXRGB (FL_BROWSER_MAXLINE - 1)
  1710. #endif
  1711.  
  1712. static rgbtriple rgbs[MAXRGB];
  1713. static int ncol;
  1714.  
  1715. /***************************************************************
  1716.  * read the rgb triplets. Only need to do this once, preferably
  1717.  * after creating the forms
  1718.  **************************************************************/
  1719. static void
  1720. read_predefined_col(void)
  1721. {
  1722.     char cname[100];        /* color name */
  1723.     rgbtriple *p = rgbs;
  1724.     int r, g, b;
  1725.     int err, j;
  1726.     FILE *fp;
  1727.  
  1728.     if (ncol != 0)
  1729.     return;
  1730.  
  1731.     if (!(fp = fopen(RGBTEXT, "r")))
  1732.     return;
  1733.  
  1734.     r = b = g = -1;
  1735.     j = 0;
  1736.     do
  1737.       {
  1738.       p->r = readint(fp);
  1739.       p->g = readint(fp);
  1740.       p->b = readint(fp);
  1741.       fgets(cname, sizeof(cname) - 1, fp);
  1742.  
  1743.       /* check if anything has gone wrong */
  1744.       err = (p->r < 0 || p->g < 0 || p->b < 0) || j >= (MAXRGB - 1);
  1745.       if (err)
  1746.           continue;
  1747.  
  1748.       /* there maybe repeats, remove it */
  1749.       if (r - p->r || g - p->g || b - p->b)
  1750.         {            /* different */
  1751.         r = p->r;
  1752.         g = p->g;
  1753.         b = p->b;
  1754.         p++;
  1755.         j++;
  1756.         fl_add_browser_line(pcc, de_space_de(cname));
  1757.         }
  1758.       }
  1759.     while (!err);
  1760.     ncol = j;
  1761.     fclose(fp);
  1762. }
  1763.  
  1764.  
  1765. /***************************************************************
  1766.  * predefc_cb is called by clicking mouse inside the browser,
  1767.  * we look up the color by examing the line number in browser
  1768.  **************************************************************/
  1769. /*ARGSUSED*/
  1770. static void
  1771. predefc_cb(FL_OBJECT * ob, long q)
  1772. {
  1773.     int i = fl_get_browser(ob);
  1774.     rgbtriple *rgb;
  1775.  
  1776.     --i;            /* first line in browser is 1 */
  1777.     if (i >= 0 && i < ncol)
  1778.       {
  1779.       rgb = rgbs + i;
  1780.       /* handle it by chaning slider value */
  1781.       set_rgb_slider(rgb->r, rgb->g, rgb->b);
  1782.       slider_cb(0, 0);
  1783.       namedcolor = 1;
  1784.       }
  1785. }
  1786.  
  1787. /****************************************************************
  1788.  * Finish up predefined color
  1789.  ****************************************************************/
  1790.  
  1791. /* ARGSUSED */
  1792. static void
  1793. predefc_done(FL_OBJECT * ob, long q)
  1794. {
  1795.     bit_hide_form(predefc);
  1796.     fl_deselect_browser(pcc);
  1797. }
  1798.  
  1799. /************************************************************
  1800.  * select_predefined is called by the RGB form
  1801.  * Really does not do anything except lending its prototype
  1802.  ************************************************************/
  1803.  
  1804. /*ARGSUSED */
  1805. static void
  1806. select_predefined(FL_OBJECT * ob, long q)
  1807. {
  1808.     read_predefined_col();
  1809.     bit_show_form(predefc, FL_PLACE_MOUSE, 0, "");
  1810. }
  1811.  
  1812. /*****************************************************************
  1813.  *
  1814.  * END OF RGBCOLOR selection
  1815.  *
  1816.  **************************************************************}*/
  1817.  
  1818. /**************************************************************
  1819.  * Select color from a colormap.
  1820.  *
  1821.  **************************************************************/
  1822.  
  1823. #define  CM_CC  301        /* CM_CACEL color          */
  1824. #define  CIOFF  350        /* offset into fl_colormap */
  1825. enum
  1826. {
  1827.     CM_RI = CIOFF - 5, CM_GI, CM_BI, CM_GR
  1828. };
  1829.  
  1830. static int cm_border = 1;
  1831. static CMPTR map;
  1832. static FL_FORM *cm_form;
  1833. static FL_OBJECT *cm_ok, *cm_cancel;
  1834. static FL_OBJECT *cm_r, *cm_g, *cm_b, *cm_i, *cm_gr, *bcol[64];
  1835. static FL_OBJECT *showmap;
  1836. static int cc;            /* start of the colormap shown   */
  1837. static int ci;            /* current index in colormap     */
  1838. static int *cccmap;        /* pointer to input array        */
  1839. static int ccbuf[4];        /* cancel                        */
  1840.  
  1841. static void select_entry(FL_OBJECT *, long);
  1842.  
  1843. /*****************************************************************
  1844.  * Install a colormap for FORM use
  1845.  *****************************************************************/
  1846. static void
  1847. set_fl_cmap(CMPTR m)
  1848. {
  1849.     int i = m->colors;
  1850.     pc_t *red = m->ct[0], *green = m->ct[1], *blue = m->ct[2];
  1851.  
  1852.     while (--i >= 0)
  1853.     fl_mapcolor(i + CIOFF, red[i], green[i], blue[i]);
  1854.  
  1855. }
  1856.  
  1857. /***************************************************************
  1858.  * Change a single entry i
  1859.  **************************************************************/
  1860.  
  1861. /* Change a single entry in fl colormap */
  1862. static void
  1863. set_fl_icmap(CMPTR m, int i)
  1864. {
  1865.     if (i >= 0 && i < m->colors)
  1866.     fl_mapcolor(i + CIOFF, m->ct[0][i], m->ct[1][i], m->ct[2][i]);
  1867. }
  1868.  
  1869.  
  1870. /********************************************************************
  1871.  * Show the current selection (marked with a cross) and its index number,
  1872.  * red, green, blue intensity as well as its equivalent grayscale intensity
  1873.  *********************************************************************/
  1874. static void
  1875. show_selection(CMPTR m, int j)
  1876. {
  1877.     int c = cc + CIOFF, gray;
  1878.     int i;
  1879.     static int lastci = -1;
  1880.  
  1881.     /* remove last mark */
  1882.     if (lastci != j && lastci >= cc && lastci < cc + 64)
  1883.       {
  1884.       i = lastci - cc;
  1885.       fl_set_object_color(bcol[i], c + i, c + i);
  1886.       fl_set_object_label(bcol[i], "");
  1887.       }
  1888.  
  1889.     i = j - cc;
  1890.  
  1891.     /* show current mark */
  1892.     if (i >= 0 && i < 64)
  1893.       {
  1894.       fl_set_object_color(bcol[i], c + i, c + i);
  1895.       fl_set_object_label(bcol[i], "@9plus");
  1896.       fl_set_object_color(cm_ok, c + i, 47);
  1897.       }
  1898.  
  1899.     lastci = j;
  1900.     fl_set_object_label(cm_i, itoa(j + 1));
  1901.     fl_set_object_label(cm_r, itoa(m->ct[0][j]));
  1902.     fl_set_object_label(cm_g, itoa(m->ct[1][j]));
  1903.     fl_set_object_label(cm_b, itoa(m->ct[2][j]));
  1904.     gray = rgb2gray(m->ct[0][ci], m->ct[1][j], m->ct[2][j]);
  1905.     fl_set_object_label(cm_gr, itoa(gray));
  1906. }
  1907.  
  1908. /*******************************************************
  1909.  * Redraw or remap the colormap. parameter t is the currentlu
  1910.  * selected entry, in absolute terms, i.e., real map entry
  1911.  *******************************************************/
  1912. static void
  1913. init_colors(CMPTR m, int t)
  1914. {
  1915.     int i, c = cc + CIOFF;
  1916.  
  1917.     fl_freeze_form(cm_form);
  1918.     for (i = 0; i < 64; i++)
  1919.       {
  1920.       fl_set_object_color(bcol[i], c + i, c + i);
  1921.       fl_set_object_label(bcol[i], "");
  1922.       }
  1923.  
  1924.     if (t >= cc && t < cc + 64)
  1925.     show_selection(m, t);
  1926.     fl_unfreeze_form(cm_form);
  1927. }
  1928.  
  1929. /* To set to an entry non-interactively */
  1930. static void
  1931. set_cmapcolor(int c[])
  1932. {
  1933.     if (c[3] < 0 || c[3] >= imgptr->cmap->colors)
  1934.     c[3] = imgptr->cmap->colors / 2;
  1935.  
  1936.     /* show it */
  1937.     ci = c[3];
  1938.     cc = 64 * (ci / 64);
  1939.  
  1940.     /* remap the color */
  1941.     set_fl_icmap(imgptr->cmap, ci);
  1942.  
  1943.     /* show it */
  1944.     init_colors(imgptr->cmap, ci);
  1945.  
  1946.     /* service color change */
  1947.     if (cmapcolor_cb)
  1948.     cmapcolor_cb(c);
  1949. }
  1950.  
  1951.  
  1952. static void map_done(FL_OBJECT *, long);
  1953.  
  1954. static void
  1955. hide_cmap_form(void)
  1956. {
  1957.     create_the_forms();
  1958.     if (cm_form->visible)
  1959.     map_done(0, 0);
  1960. }
  1961.  
  1962.  
  1963. /*ARGSUSED*/
  1964. static void
  1965. draw_cmap_cancel(CMPTR m, int c)
  1966. {
  1967.     fl_mapcolor(CM_CC, m->ct[0][c], m->ct[1][c], m->ct[2][c]);
  1968.     fl_redraw_object(cm_cancel);
  1969. }
  1970.  
  1971. /****************************************************
  1972.  *  show current colormap ramp
  1973.  ***************************************************/
  1974. static void
  1975. show_cmap_all_entries(CMPTR m)
  1976. {
  1977.     int i;
  1978.  
  1979.     fl_freeze_form(cm_form);
  1980.     fl_clear_chart(showmap);
  1981.     for (i = 0; i < m->colors; i++)
  1982.     fl_add_chart_value(showmap, 1.0, "", CIOFF + i);
  1983.     fl_unfreeze_form(cm_form);
  1984. }
  1985.  
  1986.  
  1987. static int
  1988. search_map(int k)
  1989. {
  1990.     if (k >= map->colors)
  1991.     k &= (PCMAX - 1);
  1992.     return (k >= map->colors) ? -1 : k;
  1993. }
  1994.  
  1995. /*****************************************************************
  1996.  * How to handle GL q event in cmap mode
  1997.  *****************************************************************/
  1998. /*ARGSUSED*/
  1999. static long
  2000. cmap_pick_pix(long dev, short val)
  2001. {
  2002.     int xx, yy, lx = -1, ly = -1, id;
  2003.     ci_t c;
  2004.  
  2005.     do
  2006.       {
  2007.       WHERE_R2W(xx, yy, win_xo, win_yo);
  2008.       if (lx - xx || ly - yy)
  2009.         {
  2010.         lx = xx;
  2011.         ly = yy;
  2012.         show_mouse_position(xx, yy);
  2013.         rectread(xx, yy, xx, yy, &c);
  2014.         c &= (MAXCML - 1);
  2015.         if ((id = search_map(c)) >= 0)
  2016.           {
  2017.               cc = 64 * (id / 64);
  2018.               ci = id;
  2019.               init_colors(map, id);
  2020.               /* same as a new selection */
  2021.               select_entry(0, id - cc);
  2022.           }
  2023.         }
  2024.       }
  2025.     while (control_down && mouse_down);
  2026.     fl_qreset();
  2027.     return 0;
  2028. }
  2029.  
  2030. static long
  2031. cm_fl_event(long dev, short val)
  2032. {
  2033.     long cq = dev;
  2034.  
  2035.     /* if not meant for this routine, return siliently */
  2036.  
  2037.     if (!cm_form || !cm_form->visible)
  2038.     return dev;
  2039.  
  2040.     switch (dev)
  2041.       {
  2042.       case LEFTMOUSE:
  2043.       case MIDDLEMOUSE:
  2044.       if (val && control_down)
  2045.         {
  2046.         cq = cmap_pick_pix(dev, val);
  2047.         }
  2048.       break;
  2049.       case LEFTCTRLKEY:
  2050.       case RIGHTCTRLKEY:
  2051.       if (val)
  2052.         {
  2053.         set_cursor(win_id, CUR_S_CROSS);
  2054.         do
  2055.           {
  2056.               if (mouse_down)
  2057.               cq = cmap_pick_pix(dev, val);
  2058.           }
  2059.         while (control_down);
  2060.         /* control is released, reset cursor */
  2061.         reset_cursor(win_id);
  2062.         cq = 0;
  2063.         }
  2064.       break;
  2065.       }
  2066.     if (cq)            /* still not consumed */
  2067.     cq = cmapcolor_glcb ? cmapcolor_glcb(dev, val) : dev;
  2068.     return cq;
  2069. }
  2070.  
  2071. /***********************************************************
  2072.  * a entry is selected via mouse click.
  2073.  * MUST not refer to ob, use bcol[i] instead.
  2074.  ************************************************************/
  2075. /*ARGSUSED*/
  2076. static void
  2077. select_entry(FL_OBJECT * ob, long i)
  2078. {
  2079.  
  2080.     if (i < 64 && cc + i < map->colors)
  2081.       {
  2082.       if (ci - cc >= 0 && ci - cc < 64)
  2083.           fl_set_object_label(bcol[ci - cc], "");
  2084.       ci = cc + i;
  2085.       }
  2086.  
  2087.     cccmap[0] = ccbuf[0] = map->ct[0][ci];
  2088.     cccmap[1] = ccbuf[1] = map->ct[1][ci];
  2089.     cccmap[2] = ccbuf[2] = map->ct[2][ci];
  2090.     cccmap[3] = ccbuf[3] = ci;
  2091.  
  2092.     draw_cmap_cancel(map, ci);
  2093.     show_selection(map, ci);
  2094.  
  2095.     /* handle this color change */
  2096.     if (cmapcolor_cb)
  2097.     cmapcolor_cb(cccmap);
  2098. }
  2099.  
  2100. /******************************************************************
  2101.  * The global function that gets called. After this routine cindex
  2102.  * must hold a valid value, ie., a value no more than map->colors.
  2103.  ********************************************************************/
  2104. int
  2105. get_cmapcolor(IPTR im, int clr[], int block)
  2106. {
  2107.     CMPTR m = im->cmap;
  2108.     int place = block ? FL_PLACE_MOUSE : FL_PLACE_SIZE;
  2109.  
  2110.     create_the_forms();
  2111.  
  2112.     if (!(map = m))
  2113.     return -1;
  2114.  
  2115.     set_current_color = set_cmapcolor;
  2116.  
  2117.     /* make a copy of the input color */
  2118.     ccbuf[0] = clr[0];
  2119.     ccbuf[1] = clr[1];
  2120.     ccbuf[2] = clr[2];
  2121.  
  2122.     /* if bad index on input, choose something reasonable */
  2123.     if (clr[3] < 0 || clr[3] >= map->colors)
  2124.     clr[3] = map->colors / 2;
  2125.  
  2126.     ci = ccbuf[3] = clr[3];
  2127.     cc = 64 * (ci / 64);
  2128.  
  2129.  
  2130.     /* alias */
  2131.     cccmap = clr;
  2132.  
  2133.     if (block)
  2134.       {
  2135.       fl_deactivate_all_forms();
  2136.       fl_activate_form(rgb_form);
  2137.       }
  2138.  
  2139.     if (!cm_form->visible)    /* first entry */
  2140.       {
  2141.       set_fl_cmap(map);
  2142.       install_GLQ_handler(cm_fl_event);
  2143.       show_cmap_all_entries(m);
  2144.       draw_cmap_cancel(m, ci);
  2145.       }
  2146.  
  2147.     init_colors(map, ci);
  2148.  
  2149.     bit_show_form(cm_form, place, cm_border, "ColorMap");
  2150.  
  2151.     if (block)            /* returns only if OK is pressed */
  2152.       {
  2153.       int cmfinish;
  2154.       short val;
  2155.       do
  2156.         {
  2157.         cmfinish = (fl_do_forms() == FL_EVENT) &&
  2158.             (bit_qread(&val) == F1KEY && val == 100);
  2159.         }
  2160.       while (!cmfinish);
  2161.       fl_activate_all_forms();
  2162.       }
  2163.     return 0;
  2164. }
  2165.  
  2166. /***************************************************************
  2167.  * advance or backup 64 entries
  2168.  ***************************************************************/
  2169.  /* ARGSUSED */
  2170. static void
  2171. flip_map(FL_OBJECT * ob, long q)
  2172. {
  2173.     if (q == -1)
  2174.       {                /* backup */
  2175.       if (cc >= 64)
  2176.           cc -= 64;
  2177.       }
  2178.     else
  2179.       {
  2180.       if (cc < map->colors - 64)
  2181.           cc += 64;
  2182.       }
  2183.     init_colors(map, ci);
  2184. }
  2185.  
  2186.  
  2187. /************************************************************
  2188.  * finish up
  2189.  ***********************************************************/
  2190. /*ARGSUSED*/
  2191. static void
  2192. map_done(FL_OBJECT * ob, long q)
  2193. {
  2194.     if (cm_form->visible)
  2195.       {
  2196.       reset_cursor(win_id);
  2197.       cmapcolor_cb = 0;
  2198.       cmapcolor_glcb = 0;
  2199.       remove_GLQ_handler(cm_fl_event);
  2200.       bit_hide_form(cm_form);
  2201.       fl_qenter(F1KEY, 100);
  2202.       }
  2203. }
  2204.  
  2205. /****************************************************
  2206.  * call back routine when cancel button is pressed
  2207.  * Cancel button is shown only in editmap mode
  2208.  ***************************************************/
  2209.  
  2210. /*ARGSUSED*/
  2211. static void
  2212. map_cancel(FL_OBJECT * ob, long q)
  2213. {
  2214.     ci = cccmap[3] = ccbuf[3];
  2215.     cc = 64 * (ci / 64);
  2216.  
  2217.     map->ct[0][ci] = cccmap[0] = ccbuf[0];
  2218.     map->ct[1][ci] = cccmap[1] = ccbuf[1];
  2219.     map->ct[2][ci] = cccmap[2] = ccbuf[2];
  2220.  
  2221.     /* remap the colors */
  2222.     set_fl_icmap(map, ci);
  2223.  
  2224.     /* redraw it */
  2225.     show_selection(map, ci);
  2226.  
  2227.     /* service this color change */
  2228.     if (cmapcolor_cb)
  2229.     cmapcolor_cb(ccbuf);
  2230. }
  2231.  
  2232. /*****************************************************************
  2233.  *  Edit colormap
  2234.  *****************************************************************/
  2235.  
  2236. static IPTR lim;
  2237.  
  2238. /* need two buffers to do the magic */
  2239. static currentci[4];
  2240. static currentrgb[4];
  2241.  
  2242. /************************************************************
  2243.  * What to do when slider changes
  2244.  ************************************************************/
  2245. static void
  2246. rgb_change_cb(int c[])
  2247. {
  2248.     ci_t i = currentci[3];
  2249.  
  2250.     /* change the colormap */
  2251.     lim->cmap->ct[0][i] = c[0];
  2252.     lim->cmap->ct[1][i] = c[1];
  2253.     lim->cmap->ct[2][i] = c[2];
  2254.  
  2255.     /* change the shown colormap selector entry */
  2256.     set_fl_icmap(lim->cmap, i);
  2257.     show_selection(lim->cmap, i);
  2258.  
  2259.     /* change image as well */
  2260.     mapcolor(i, c[0], c[1], c[2]);
  2261. }
  2262.  
  2263. /**********************************************************
  2264.  * What to do when a new entry is selected
  2265.  **********************************************************/
  2266. static void
  2267. ci_change_cb(int c[])
  2268. {
  2269.     set_rgb_slider(c[0], c[1], c[2]);
  2270.  
  2271.     if (c != currentci)
  2272.       {
  2273.       currentci[0] = c[0];
  2274.       currentci[1] = c[1];
  2275.       currentci[2] = c[2];
  2276.       currentci[3] = c[3];
  2277.       rgb_change_cb(c);
  2278.       }
  2279. }
  2280.  
  2281.  
  2282. /*****************************************************************
  2283.  * Global entry for map editing
  2284.  ******************************************************************/
  2285. int
  2286. do_editmap(IPTR im)
  2287. {
  2288.  
  2289.     create_the_forms();
  2290.  
  2291.     if (!IS_CI(im))
  2292.       {
  2293.       Bark("EditMap", "%s: not a colormapped image", im->ifile);
  2294.       return -1;
  2295.       }
  2296.  
  2297.     lim = im;
  2298.  
  2299.     fl_show_object(cm_cancel);
  2300.  
  2301.     /* what to do if RGB changes */
  2302.     rgbcolor_cb = rgb_change_cb;
  2303.     get_RGBcolor(im, currentrgb, 0);
  2304.  
  2305.     /* OK has no utility, neither does cancel */
  2306.     fl_deactivate_object(ok_butt);
  2307.     fl_hide_object_only(cancel);
  2308.  
  2309.     /*
  2310.      * since we are editing colormaps, the image is in colormap, do not want
  2311.      * to have the rgb_fl_event to be active
  2312.      */
  2313.  
  2314.     remove_GLQ_handler(rgb_fl_event);
  2315.  
  2316.     cmapcolor_cb = ci_change_cb;
  2317.     get_cmapcolor(im, currentci, 1);
  2318.  
  2319.  
  2320.     /* hide_rgb_form will try to remove GLQ, it bitches */
  2321.     install_GLQ_handler(rgb_fl_event);
  2322.     fl_activate_object(ok_butt);
  2323.     hide_rgb_form();
  2324.  
  2325.     /* restore the default */
  2326.     fl_show_object(cancel);
  2327.     fl_show_object(cm_cancel);
  2328.  
  2329.     return 0;
  2330. }
  2331.  
  2332.  
  2333. /****************************************************************
  2334.  * main form for cmap color selection
  2335.  ****************************************************************/
  2336. static void
  2337. create_cmap_form(void)
  2338. {
  2339.     int i, j, k = 18, l;
  2340.     float dx, dy, x, y, dch = 20;
  2341.     FL_OBJECT *o, *cm_c[6];
  2342.     FL_OBJECT *obj;
  2343.  
  2344.     cm_form = fl_bgn_form(FL_UP_BOX, 266.0, k + 240.0 + dch + 5);
  2345.     o = fl_add_button(FL_HIDDEN_BUTTON, 0, 0, 240, k + 240, "");
  2346.     fl_set_call_back(o, help_cb, HELP_COLOR);
  2347.  
  2348.     /* showmap */
  2349.     showmap = fl_add_chart(FL_FILLED_CHART, 5, k + 234, 256, dch, "");
  2350.     fl_set_object_boxtype(showmap, FL_FLAT_BOX);
  2351.     /* flip backward */
  2352.     obj = fl_add_button(FL_NB, 10.0, k + 50.0, 35.0, 178.0, "@4");
  2353.     fl_set_object_lcol(obj, 3);
  2354.     fl_set_call_back(obj, flip_map, -1);
  2355.  
  2356.     dx = dy = 22.0;
  2357.     for (i = 0; i < 8; i++)
  2358.       {
  2359.       for (j = 0; j < 8; j++)
  2360.         {
  2361.         x = 45.0 + dx * j;
  2362.         y = k + 205.0 - dy * i;
  2363.         l = 8 * i + j;
  2364.  
  2365.         bcol[l] = obj = fl_add_button(FL_NB, x, y, dx, dy, "");
  2366.         fl_set_object_boxtype(obj, FL_BORDER_BOX);
  2367.         fl_set_object_lcol(obj, 7);
  2368.         fl_set_call_back(obj, select_entry, l);
  2369.  
  2370.         }
  2371.       }
  2372.  
  2373.     /* flip forward */
  2374.     obj = fl_add_button(FL_NB, 45 + dx * 8, k + 50.0, 35.0, 178.0, "@6");
  2375.     fl_set_object_lcol(obj, 3);
  2376.     fl_set_call_back(obj, flip_map, 1);
  2377.  
  2378.     cm_cancel = obj = fl_add_button(FL_NB, 20.0, 10.0, 90.0, 30.0, "Cancel");
  2379.     fl_set_call_back(obj, map_cancel, 0);
  2380.     fl_set_object_color(obj, CM_CC, FL_RED);
  2381.     fl_set_object_lcol(obj, FL_GREEN);
  2382.  
  2383.     cm_ok = obj = fl_add_button(FL_NB, 150.0, 10.0, 90.0, 30.0, "OK");
  2384.     fl_set_call_back(obj, map_done, 0);
  2385.     fl_set_object_lcol(cm_ok, FL_MAGENTA);
  2386.     fl_set_object_lstyle(cm_ok, FL_BOLD_STYLE);
  2387.  
  2388.     /* the following four are the colorindex, red, green, blue */
  2389.     dx = 47.0;
  2390.     dy = 20.0;
  2391.     for (x = 13, y = 45, i = 0; i < 5; i++, x += dx)
  2392.       {
  2393.       cm_c[i] = o = fl_add_text(FL_NORMAL_TEXT, x, y, dx, dy, "");
  2394.       fl_set_object_boxtype(o, FL_BORDER_BOX);
  2395.       fl_set_object_lstyle(o, FL_BOLD_STYLE);
  2396.       fl_set_object_align(o, FL_ALIGN_CENTER);
  2397.       }
  2398.     cm_i = cm_c[0];
  2399.     fl_set_object_lcol(cm_i, 0);
  2400.     cm_r = cm_c[1];
  2401.     fl_set_object_lcol(cm_r, 7);
  2402.     cm_g = cm_c[2];
  2403.     fl_set_object_lcol(cm_g, 0);
  2404.     cm_b = cm_c[3];
  2405.     fl_set_object_lcol(cm_b, 7);
  2406.     cm_gr = cm_c[4];
  2407.     fl_set_object_lcol(cm_gr, 0);
  2408.     fl_end_form();
  2409.  
  2410.     fl_mapcolor(CM_RI, 255, 0, 0);
  2411.     fl_mapcolor(CM_GI, 0, 255, 0);
  2412.     fl_mapcolor(CM_BI, 0, 0, 255);
  2413.     fl_mapcolor(CM_GR, 200, 200, 200);
  2414.     fl_set_object_color(cm_r, CM_RI, CM_RI);
  2415.     fl_set_object_color(cm_g, CM_GI, CM_GI);
  2416.     fl_set_object_color(cm_b, CM_BI, CM_BI);
  2417.     fl_set_object_color(cm_gr, CM_GR, CM_GR);
  2418.  
  2419.     /* hide cancel by default */
  2420.     fl_hide_object(cm_cancel);
  2421. }
  2422.  
  2423.  
  2424. /***************************************************************
  2425.  * FORMS for predefined colors: a browser & a button
  2426.  **************************************************************/
  2427. static void
  2428. create_form_predefc(void)
  2429. {
  2430.     FL_OBJECT *obj;
  2431.  
  2432.     predefc = fl_bgn_form(FL_NO_BOX, 195.0, 255.0);
  2433.     obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 195.0, 255.0, "");
  2434.     pcc = obj = fl_add_browser(FL_HBR, 20.0, 40.0, 140.0, 200.0, "");
  2435.     fl_set_object_boxtype(obj, FL_SHADOW_BOX);
  2436.     fl_set_call_back(obj, predefc_cb, 0);
  2437.     fl_set_browser_fontsize(pcc, 10.0);
  2438.  
  2439.     obj = fl_add_button(FL_NB, 120.0, 10.0, 60.0, 25.0, "Done");
  2440.     fl_set_object_lsize(obj, 10.0);
  2441.     fl_set_call_back(obj, predefc_done, 0);
  2442.     fl_end_form();
  2443.  
  2444.     /* load the color definations */
  2445. }
  2446.  
  2447.  
  2448. /****************************************************************
  2449.  * Main RGB form
  2450.  *****************************************************************/
  2451. static void
  2452. create_rgb_form(void)
  2453. {
  2454.     FL_OBJECT *obj;
  2455.     float x = 10, dx = 320, dy = 30.0;
  2456.     int i;
  2457.  
  2458.     rgb_form = fl_bgn_form(FL_NO_BOX, 400.0, 170.0);
  2459.     obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 400.0, 170.0, "");
  2460.  
  2461.     /* three mixers */
  2462.     slider[0] = obj = fl_add_valslider(FL_HFS, x, 10.0, dx, dy, "");
  2463.     fl_set_object_color(obj, 47, FL_RED);
  2464.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  2465.     fl_set_call_back(obj, slider_cb, 0);
  2466.  
  2467.     slider[1] = obj = fl_add_valslider(FL_HFS, x, 50.0, dx, dy, "");
  2468.     fl_set_object_color(obj, 47, FL_GREEN);
  2469.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  2470.     fl_set_call_back(obj, slider_cb, 1);
  2471.  
  2472.     slider[2] = obj = fl_add_valslider(FL_HFS, x, 90.0, dx, dy, "");
  2473.     fl_set_object_color(obj, 47, FL_BLUE);
  2474.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  2475.     fl_set_call_back(obj, slider_cb, 2);
  2476.  
  2477.     ok_butt = obj = fl_add_button(FL_NB, 340.0, 10.0, 50.0, 110.0, "OK");
  2478.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  2479.     fl_set_object_color(obj, OK_I, 47);
  2480.     fl_set_object_lcol(obj, FL_MAGENTA);
  2481.     fl_set_call_back(obj, ok_cb, 0);
  2482.  
  2483.     dx = 100.0;
  2484.     dy = 30.0;
  2485.     obj = fl_add_button(FL_NB, 20.0, 130.0, dx, dy, "ColorHelp");
  2486.  
  2487.     fl_set_call_back(obj, help_cb, HELP_COLOR);
  2488.     fl_set_object_lsize(obj, 10.0);
  2489.  
  2490.     obj = fl_add_button(FL_NB, 20 + dx, 130, dx, dy, "PreDefCol");
  2491.     fl_set_call_back(obj, select_predefined, 0);
  2492.     fl_set_object_lsize(obj, 10.0);
  2493.  
  2494.     cancel = obj = fl_add_button(FL_NB, 20 + 2 * dx, 130.0, dx, dy, "Cancel");
  2495.     fl_set_object_color(obj, CAN_I, 47);
  2496.     fl_set_object_lsize(obj, 10.0);
  2497.     fl_set_object_lcol(obj, FL_CYAN);
  2498.     fl_set_call_back(obj, cancel_cb, 0);
  2499.     fl_end_form();
  2500.  
  2501.     /* default properties */
  2502.     for (i = 0; i < 3; i++)
  2503.       {
  2504.       fl_set_slider_bounds(slider[i], 0.0, PCMAXV);
  2505.       fl_set_slider_value(slider[i], 0.0);
  2506.       fl_set_slider_precision(slider[i], 0);
  2507.       fl_set_slider_step(slider[i], 1.0);
  2508.       }
  2509. }
  2510.  
  2511.  
  2512. static void
  2513. create_the_forms(void)
  2514. {
  2515.     static int fmade;
  2516.  
  2517.     if (!fmade)
  2518.       {
  2519.       create_rgb_form();
  2520.       create_form_predefc();
  2521.       create_cmap_form();
  2522.       fmade = 1;
  2523.       }
  2524. }
  2525.